package cn.ztuo.bitrade.service;

import cn.ztuo.bitrade.constant.*;
import cn.ztuo.bitrade.dao.*;
import cn.ztuo.bitrade.entity.*;
import cn.ztuo.bitrade.exception.AuthenticationException;
import cn.ztuo.bitrade.pagination.Criteria;
import cn.ztuo.bitrade.pagination.PageResult;
import cn.ztuo.bitrade.pagination.Restrictions;
import cn.ztuo.bitrade.service.Base.BaseService;
import cn.ztuo.bitrade.util.BigDecimalUtils;
import cn.ztuo.bitrade.util.Md5;
import cn.ztuo.bitrade.vo.ChannelVO;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


@Slf4j
@Service
public class MemberService extends BaseService {

    @Autowired
    private MemberDao memberDao;

    @Autowired
    private MemberSignRecordDao signRecordDao;

    @Autowired
    private MemberTransactionDao transactionDao;

    @Autowired
    private RelationService relationService;

    @Autowired
    private IeoLevelDao ieoLevelDao;

    @Autowired
    private IeoOdfrecordDao ieoOdfrecordDao;

    @Autowired
    private AwardService awardService;

    @Autowired
    private SysCfService sysCfService;
    /**
     * 条件查询对象 pageNo pageSize 同时传时分页
     *
     * @param booleanExpressionList
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Transactional(readOnly = true)
    public PageResult<Member> queryWhereOrPage(List<BooleanExpression> booleanExpressionList, Integer pageNo, Integer pageSize) {
        List<Member> list;
        JPAQuery<Member> jpaQuery = queryFactory.selectFrom(QMember.member)
                .where(booleanExpressionList.toArray(new BooleanExpression[booleanExpressionList.size()]));
        jpaQuery.orderBy(QMember.member.id.desc());
        if (pageNo != null && pageSize != null) {
            list = jpaQuery.offset((pageNo - 1) * pageSize).limit(pageSize).fetch();
        } else {
            list = jpaQuery.fetch();
        }
        return new PageResult<>(list, jpaQuery.fetchCount());
    }

    public Member save(Member member) {
        return memberDao.saveAndFlush(member);
    }

    public List<Member> findAll(Predicate predicate){
        //return Collections.;
        Iterable<Member> iterable = memberDao.findAll(predicate);
        List<Member> list = IteratorUtils.toList(iterable.iterator());
        return list ;
    }




    public Member saveAndFlush(Member member) {
        return memberDao.saveAndFlush(member);
    }

    @Transactional(rollbackFor = Exception.class)
    public Member loginWithToken(String token, String ip, String device) {
        if (StringUtils.isBlank(token)) {
            return null;
        }
        //Member mr = memberDao.findMemberByTokenAndTokenExpireTimeAfter(token,new Date());
        Member mr = memberDao.findMemberByToken(token);
        return mr;
    }

    public Member login(String username, String password) throws Exception {
        Member member = memberDao.findMemberByMobilePhoneOrEmail(username, username);
        if (member == null) {
            throw new AuthenticationException("账号或密码错误");
        } else if (member.getLoginLock()!=null&&member.getLoginLock().equals(BooleanEnum.IS_TRUE)){
            throw new AuthenticationException("多次输入错误的密码，账号已锁定，请联系客服解锁或找回密码解锁");
        } else if (!Md5.md5Digest(password + member.getSalt()).toLowerCase().equals(member.getPassword())) {
            log.info("账号或密码错误");
            return null;
        } else if (member.getStatus().equals(CommonStatus.ILLEGAL)) {
            throw new AuthenticationException("该帐号已经被禁用，请联系客服");
        }
        return member;
    }

    /**
     * 获取当前用户1级和2级子用户列表
     * @param id 用户ID
     * @param level 1=直推1级，2=间推2级
     * @return
     */
    public Set<Long> childs(Long id,Long level){
        HashSet<Long> set = new HashSet<>();
        List<Member> members = new ArrayList<>();
        if(level==1){
            members =  memberDao.findAllByInviterId(id);
        }else{
            members =  memberDao.findAllByInviterParentId(id);
        }
        if(members==null) return set;
        members.stream().filter(info->relationService.findActivation(info.getId())).forEach(info->set.add(info.getId()));
        return set;
    }

    /**
     * 获取当前用户1级和2级子用户列表，并屏蔽到USDT激活的用户
     * @param id
     * @param level
     * @return
     */
    public Set<Long> childsTwo(Long id,Long level){
        HashSet<Long> set = new HashSet<>();
        List<Member> members = new ArrayList<>();
        if(level==1){
            members =  memberDao.findAllByInviterId(id);
        }else{
            members =  memberDao.findAllByInviterParentId(id);
        }
        if(members==null) return set;
        members.stream().filter(info->{
            Boolean is = relationService.findActivation(info.getId());
            if(!is) return false;
            Award award = awardService.findByUidAndType(info.getId(),1L);
            if(award==null)return false;
            if(award.getUnit().equals("USDT")){
                return false;
            }else {
                return true;
            }
        }).forEach(info->set.add(info.getId()));
        return set;
    }

    /**
     * 获取用户的认购额度只限类型为4的IEO
     * @param id
     * @return
     */
    public BigDecimal ieoQuoda(Long id){
        BigDecimal er = BigDecimal.ZERO;
        Award info = awardService.findByUidAndType(id,1L);
        if(info.getUnit().equals("ODF")){
          SysCf config =  sysCfService.configOneCname("zengsong");
          er = new BigDecimal(config.getValue());
        }
        //直推一级人数
        int ones=  this.childsTwo(id,1L).size();
        //直推二级人数
        int twos=  this.childsTwo(id,2L).size();
        List<IeoLevel> levels =  ieoLevelDao.selecAll();
        BigDecimal number = BigDecimal.ZERO;
 
        for(IeoLevel ieo:levels){
            if(ones>2) {
                //直推大于两人的,每多一个人多30额度
                BigDecimal zhitui = BigDecimalUtils.sub(new BigDecimal(ones),new BigDecimal("2"));
                BigDecimal zhituiSum = BigDecimalUtils.mul(zhitui,ieo.getNumber());
                IeoLevel levelInfo = ieoLevelDao.findOne(2L);
                number = BigDecimalUtils.add(zhituiSum,levelInfo.getNumber());
                break;
            }else if(ones>=ieo.getReone()){
                number = ieo.getNumber();
                break;
            }
        }

        BigDecimal jianSum = BigDecimalUtils.mul(new BigDecimal(twos),new BigDecimal("20"));
        return BigDecimalUtils.add(BigDecimalUtils.add(number,er),jianSum);
    }
    /**
     * 获取用户剩余的认购额度只限类型为4的IEO
     * @param id
     * @return
     */
    public BigDecimal ieoRemaining(Long id){
        //获取用户的限额
        BigDecimal limit =   this.ieoQuoda(id);
        //获取用户已购额度
        ArrayList<Integer> type = new ArrayList<>();
        //只获取用户认购的额度，排除节点
        type.add(4);
        BigDecimal userLimit = ieoOdfrecordDao.sumNumber(id,type);
        if(userLimit==null) userLimit = BigDecimal.ZERO;
        BigDecimal number = BigDecimal.ZERO;
        number  = BigDecimalUtils.compare(limit,userLimit)?BigDecimalUtils.sub(limit,userLimit) : BigDecimal.ZERO;
        return number;
    }

    /**
     * @author fiwork.net
     * @description
     * @date 2019/12/25 18:42
     */
    public Member findOne(Long id) {
        return memberDao.findOne(id);
    }

    /**
     * @author fiwork.net
     * @description 查询所有会员
     * @date 2019/12/25 18:43
     */
    public List<Member> findAll() {
        return memberDao.findAll();
    }



    /**
     * 查询会员总数
     * @return
     */
    public long count(){
        return memberDao.count();
    }

    public long getRegistrationNum(String date){
        return memberDao.getRegistrationNum(date);
    }

    public Page<Member> findAll(Predicate predicate, PageModel pageModel){
        return memberDao.findAll(predicate,pageModel.getPageable());
    }

    public List<Member> findPromotionMember(Long id) {
        return memberDao.findAllByInviterId(id);
    }


    public List<Member> findAllByParentsLike(String userid) {
        return memberDao.findAllByParentsLike("%|"+userid+"|%");
    }

    /**
     * @author fiwork.net
     * @description 分页
     * @date 2019/1/12 15:35
     */
    public Page<Member> page(Integer pageNo, Integer pageSize, CommonStatus status) {
        //排序方式 (需要倒序 这样    Criteria.sort("id","createTime.desc") ) //参数实体类为字段名
        Sort orders = Criteria.sortStatic("id");
        //分页参数
        PageRequest pageRequest = new PageRequest(pageNo, pageSize, orders);
        //查询条件
        Criteria<Member> specification = new Criteria<Member>();
        specification.add(Restrictions.eq("status", status, false));
        return memberDao.findAll(specification, pageRequest);
    }

    public Page<Member> page(Integer pageNo, Integer pageSize) {
        //排序方式 (需要倒序 这样    Criteria.sort("id","createTime.desc") ) //参数实体类为字段名
        Sort orders = Criteria.sortStatic("id");
        //分页参数
        PageRequest pageRequest = new PageRequest(pageNo, pageSize, orders);
        return memberDao.findAll(pageRequest);
    }

    public boolean emailIsExist(String email) {
        List<Member> list = memberDao.getAllByEmailEquals(email);
        return list.size() > 0 ? true : false;
    }

    public boolean usernameIsExist(String username) {
        return memberDao.getAllByUsernameEquals(username).size() > 0 ? true : false;
    }

    public boolean phoneIsExist(String phone) {
        return memberDao.getAllByMobilePhoneEquals(phone).size() > 0 ? true : false;
    }

    public Member findByUsername(String username) {
        return memberDao.findByUsername(username);
    }

    public Member findByEmail(String email) {
        return memberDao.findMemberByEmail(email);
    }

    public Member findByPhone(String phone) {
        return memberDao.findMemberByMobilePhone(phone);
    }

    public Member findByPhoneOrEmail(String str){
        return memberDao.findMemberByMobilePhoneOrEmail(str,str);

    }

    public Page<Member> findAll(Predicate predicate, Pageable pageable) {
        return memberDao.findAll(predicate, pageable);
    }

    public String findUserNameById(long id) {
        return memberDao.findUserNameById(id);
    }

    //签到事件
    @Transactional(rollbackFor = Exception.class)
    public void signInIncident(Member member, MemberWallet memberWallet, cn.ztuo.bitrade.entity.Sign sign) {
        member.setSignInAbility(false);//失去签到能力
        memberWallet.setBalance(BigDecimalUtils.add(memberWallet.getBalance(), sign.getAmount()));//签到收益

        // 签到记录
        signRecordDao.save(new cn.ztuo.bitrade.entity.MemberSignRecord(member, sign));
        //账单明细
        cn.ztuo.bitrade.entity.MemberTransaction memberTransaction = new cn.ztuo.bitrade.entity.MemberTransaction();
        memberTransaction.setMemberId(member.getId());
        memberTransaction.setAmount(sign.getAmount());
        memberTransaction.setType(TransactionType.ACTIVITY_AWARD);
        memberTransaction.setSymbol(sign.getCoin().getUnit());
        transactionDao.save(memberTransaction);
    }

    //重置会员签到
    public void resetSignIn() {
        memberDao.resetSignIn();
    }

    public void updateCertifiedBusinessStatusByIdList(List<Long> idList) {
        memberDao.updateCertifiedBusinessStatusByIdList(idList, CertifiedBusinessStatus.DEPOSIT_LESS);
    }

    public List<ChannelVO> getChannelCount(List<Long> memberIds){
        List<Object[]> list=memberDao.getChannelCount(memberIds);
        List<ChannelVO> channelVOList=new ArrayList<>();
        if(list!=null&&list.size()>0){
            for(Object[] objs:list){
                Number memberId=(Number)objs[0];
                Number channelCount=(Number)objs[1];
                Number channelReward=(Number)objs[2];
                ChannelVO channelVO=new ChannelVO(memberId.longValue(),channelCount.intValue(),new BigDecimal(channelReward.doubleValue()));
                channelVOList.add(channelVO);
            }
        }
        return channelVOList;
    }

    public void lock(String username){
        memberDao.updateLoginLock(username,BooleanEnum.IS_TRUE);
    }


    public void unLock(String username){
        memberDao.updateLoginLock(username,BooleanEnum.IS_FALSE);
    }

    public Integer saveWallet(String coinId,Long memberId,BigDecimal balance){
        return memberDao.saveWallet(coinId,memberId,balance);
    }

    public Member findByLuckyCode(String luckyCode){
        return memberDao.findByLuckyCode(luckyCode);
    }

    public Member findByPromotionCode(String code){
        return memberDao.findByPromotionCode(code);
    }

    public Member findByWords(String words){
        return memberDao.findByWords(words);
    }

    public boolean lockRedeem(String username,int redeem){
        return memberDao.lockRedeem(username,redeem)>0;
    }
}
